import java.util.PriorityQueue;

//模拟实现定时器
class MyTimerTask implements Comparable<MyTimerTask>{
    //任务
    private final Runnable runnable;
    //时间
    private final long time;
    public MyTimerTask(Runnable runnable,long delay){
        this.runnable = runnable;
        //这里用绝对时间会更加方便
        this.time = System.currentTimeMillis()+delay;
    }
    //重写比较方法，把时间短的放队列前面
    public int compareTo(MyTimerTask o){
        return (int)(this.time - o.time);
    }
    public long getTime(){
        return time;
    }
    public Runnable getRunnable(){
        return runnable;
    }
}

class MyTimer{
    //使用优先级队列保存所有的任务
    private final PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    //锁对象
    private final Object locker = new Object();
    //用来往队列中添加任务
    public void schedule(Runnable task,long delay){
        //因为这个队列会有两个线程对其进行操作所以需要加锁
        synchronized (locker) {
            queue.offer(new MyTimerTask(task,delay));
            //当队列不为空时唤醒线程
            locker.notify();
        }
    }
    //构造方法
    public MyTimer(){
        //创建一个“扫描线程”
    Thread t = new Thread(() ->{
        //线程需不断的查看队首元素的时间
        while (true){
            try {
                //因为这个队列会有两个线程对其进行操作所以需要加锁
                synchronized (locker) {
                    //不要使用if判断而应使用while循环wait每次被唤醒时应该再判断一下，
                    // 防止除notify以外的东西所唤醒
                    while (queue.isEmpty()){
                        //队列为空时进入阻塞状态
                        //当队列不为空时则应该被唤醒
                        locker.wait();
                    }
                    //获取队首元素
                    MyTimerTask task = queue.peek();
                    long curTime = System.currentTimeMillis();
                    //当时间到了就执行任务
                    if(curTime>=task.getTime()){
                        task.getRunnable().run();
                        //记得删除元素
                        queue.poll();
                    }else{
                        //时间没到就休眠到队首的时间（刚才操作的元素已删除）
                        //不使用sleep是因为如果此时新添加了一个任务比现在队首的时间早
                        //则应唤醒线程
                        locker.wait(task.getTime() - curTime);
                    }
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t.start();
}
}


public class demo4 {

    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();

        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(3000);

            }
        },3000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(2000);

            }
        },2000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println(1000);

            }
        },1000);
        System.out.println("程序开始执行");
    }
}
